"""
LAN对讲机主程序
"""
import sys
import os
from PyQt6.QtWidgets import QApplication, QMessageBox
from PyQt6.QtCore import QObject, pyqtSignal, QTimer

# 导入各个模块
from config.config_manager import ConfigManager
from config.startup_manager import StartupManager
from network.network_manager import NetworkManager
from audio.audio_manager import AudioManager
from ui.main_window import MainWindow
from ui.notification_windows import RecordingOverlay, SpeakingNotification
from ui.system_tray import SystemTray
from ui.hotkey_manager import HotkeyManager


class WalkieTalkieApp(QObject):
    """对讲机应用主控制器"""
    
    # 定义信号（用于线程安全的UI更新）
    audio_received_signal = pyqtSignal(str, bytes)  # user_name, audio_data
    
    def __init__(self):
        super().__init__()
        
        # 配置管理器
        self.config_manager = ConfigManager()
        
        # 网络管理器（传入config_manager以使用用户选择的IP）
        self.network_manager = NetworkManager(
            port=self.config_manager.get('port'),
            config_manager=self.config_manager
        )
        
        # 音频管理器
        self.audio_manager = AudioManager()
        
        # UI组件
        self.main_window = MainWindow(self.config_manager)
        self.recording_overlay = RecordingOverlay()
        self.speaking_notification = SpeakingNotification()
        self.system_tray = SystemTray()
        self.hotkey_manager = HotkeyManager()
        
        # 当前状态
        self.is_muted = self.config_manager.get('muted', False)
        self.is_recording = False
        
        # 语音接收状态（用于管理说话通知）
        self.last_audio_time = {}  # {user_name: last_time}
        self.audio_timeout_ms = 1000  # 1秒无音频则认为说话结束
        self.check_audio_timer = None
        
        # 连接信号和槽
        self.connect_signals()
        
        # 初始化
        self.initialize()
        
        # 启动音频超时检查定时器
        self.check_audio_timer = QTimer()
        self.check_audio_timer.timeout.connect(self._check_audio_timeout)
        self.check_audio_timer.start(500)  # 每500ms检查一次
    
    def connect_signals(self):
        """连接信号和槽"""
        # 主窗口信号
        self.main_window.create_room_signal.connect(self.on_create_room)
        self.main_window.join_room_signal.connect(self.on_join_room)
        self.main_window.leave_room_signal.connect(self.on_leave_room)
        self.main_window.settings_changed_signal.connect(self.on_settings_changed)
        
        # 系统托盘信号
        self.system_tray.show_window_signal.connect(self.main_window.show)
        self.system_tray.toggle_mute_signal.connect(self.on_toggle_mute)
        self.system_tray.quit_signal.connect(self.on_quit)
        
        # 快捷键信号
        self.hotkey_manager.hotkey_pressed.connect(self.on_hotkey_pressed)
        self.hotkey_manager.hotkey_released.connect(self.on_hotkey_released)
        
        # 内部信号连接（线程安全）
        self.audio_received_signal.connect(self._handle_audio_received_in_main_thread)
        
        # 网络管理器回调（在网络线程中被调用）
        self.network_manager.on_audio_received = self.on_audio_received
        self.network_manager.on_member_joined = self.on_member_joined
        self.network_manager.on_member_left = self.on_member_left
        self.network_manager.on_members_updated = self.on_members_updated
        
        # 音频管理器回调
        self.audio_manager.on_recording_started = self.on_recording_started
        self.audio_manager.on_recording_stopped = self.on_recording_stopped
        self.audio_manager.on_audio_chunk = self.on_audio_chunk_received  # 实时音频块
    
    def initialize(self):
        """初始化应用"""
        # 启动网络服务
        user_name = self.config_manager.get('user_name')
        if not self.network_manager.start(user_name):
            QMessageBox.critical(
                None,
                "错误",
                "无法启动网络服务，请检查端口是否被占用"
            )
            sys.exit(1)
        
        # 注册快捷键
        hotkey = self.config_manager.get('hotkey')
        self.hotkey_manager.register_hotkey(hotkey)
        
        # 更新静音状态
        self.system_tray.update_mute_status(self.is_muted)
        
        # 检查是否需要自动重连（在显示窗口前）
        auto_reconnected = False
        if self.config_manager.get('auto_rejoin'):
            room_name = self.config_manager.get('room_name')
            room_host = self.config_manager.get('room_host')
            is_host = self.config_manager.get('is_host')
            
            if room_name:
                print(f"[Main] 自动重连到房间: {room_name}")
                auto_reconnected = True
                
                if is_host:
                    # 房主：创建房间并恢复成员列表
                    # 注意：先读取历史成员，再创建房间（避免覆盖历史数据）
                    saved_members = self.config_manager.get_room_members(room_name)
                    
                    # 直接调用网络管理器创建房间，避免触发保存逻辑
                    self.network_manager.create_room(room_name)
                    self.main_window.update_room_status(room_name, True)
                    
                    # 保存房间配置（不保存成员列表）
                    self.config_manager.update(
                        room_name=room_name,
                        is_host=True,
                        room_host=self.config_manager.get_local_ip()
                    )
                    
                    # 恢复成员列表（会通知历史成员）
                    if saved_members:
                        print(f"[Main] 恢复 {len(saved_members)} 个历史成员")
                        self._restore_members(saved_members)
                    else:
                        print(f"[Main] 没有历史成员，创建新房间")
                        # 仅更新UI，不保存（避免覆盖可能的历史数据）
                        self.main_window.update_members(self.network_manager.get_members_list())
                else:
                    # 普通成员：加入房间（等待房主回复成员列表）
                    if room_host:
                        print(f"[Main] 普通成员重连，加入房间: {room_name} @ {room_host}")
                        self.on_join_room(room_name, room_host)
                        print(f"[Main] 已发送加入请求，等待房主回复成员列表...")
        
        # 检查是否开机启动且需要最小化到托盘
        start_minimized = self.config_manager.get('start_minimized', False)
        is_autostart = self.config_manager.get('is_autostart_session', False)
        
        if is_autostart and start_minimized:
            # 开机启动时直接最小化到托盘，不显示窗口
            print("[Main] 开机启动，最小化到系统托盘")
            self.config_manager.set('is_autostart_session', False)  # 重置标记
        else:
            # 正常显示主窗口
            self.main_window.show()
    
    def on_create_room(self, room_name: str):
        """创建房间"""
        self.network_manager.create_room(room_name)
        self.main_window.update_room_status(room_name, True)
        
        # 保存配置
        self.config_manager.update(
            room_name=room_name,
            is_host=True,
            room_host=self.config_manager.get_local_ip()
        )
        
        # 更新成员列表
        self.on_members_updated(self.network_manager.get_members_list())
        
        self.system_tray.show_message("房间已创建", f"房间 '{room_name}' 已成功创建")
    
    def on_join_room(self, room_name: str, host_ip: str):
        """加入房间"""
        print(f"[Main] ========== 加入房间: {room_name} @ {host_ip} ==========")
        
        try:
            # 先确保停止所有录音和播放
            if self.is_recording:
                print("[Main] 加入前停止录音...")
                self._stop_recording()
            
            self.audio_manager.stop_playback()
            print("[Main] 加入前停止播放")
            
            # 加入网络房间
            print("[Main] 正在加入网络房间...")
            self.network_manager.join_room(room_name, host_ip)
            
            # 更新UI
            self.main_window.update_room_status(room_name, False)
            
            # 保存配置
            self.config_manager.update(
                room_name=room_name,
                is_host=False,
                room_host=host_ip
            )
            
            print(f"[Main] 已成功加入房间: {room_name}")
            self.system_tray.show_message("加入房间", f"正在加入房间 '{room_name}'")
        except Exception as e:
            print(f"[Main] 加入房间失败: {e}")
            import traceback
            traceback.print_exc()
            self.system_tray.show_message("加入失败", f"加入房间失败: {e}")
    
    def on_leave_room(self):
        """离开房间"""
        print("[Main] ========== 离开房间 ==========")
        
        try:
            # 如果正在录音，先停止
            if self.is_recording:
                print("[Main] 停止当前录音...")
                self._stop_recording()
        except Exception as e:
            print(f"[Main] 停止录音异常: {e}")
        
        try:
            # 停止播放
            print("[Main] 停止音频播放...")
            self.audio_manager.stop_playback()
        except Exception as e:
            print(f"[Main] 停止播放异常: {e}")
        
        try:
            # 离开网络房间
            print("[Main] 离开网络房间...")
            self.network_manager.leave_room()
        except Exception as e:
            print(f"[Main] 离开网络房间异常: {e}")
        
        # 更新UI
        self.main_window.update_left_room()
        
        # 清空房间状态配置
        self.config_manager.clear_room_state()
        
        print("[Main] 已成功离开房间")
        self.system_tray.show_message("离开房间", "已离开房间")
    
    def on_settings_changed(self, settings: dict):
        """设置更改"""
        # 更新用户名
        user_name = settings.get('user_name')
        if user_name:
            self.config_manager.set('user_name', user_name)
            self.main_window.update_user_info(
                user_name,
                self.config_manager.get('hotkey')
            )
        
        # 更新快捷键
        new_hotkey = settings.get('hotkey')
        if new_hotkey and new_hotkey != self.config_manager.get('hotkey'):
            self.config_manager.set('hotkey', new_hotkey)
            self.hotkey_manager.register_hotkey(new_hotkey)
            self.main_window.update_user_info(
                self.config_manager.get('user_name'),
                new_hotkey
            )
        
        # 更新录音模式
        new_mode = settings.get('hotkey_mode')
        if new_mode and new_mode != self.config_manager.get('hotkey_mode'):
            self.config_manager.set('hotkey_mode', new_mode)
            mode_name = "切换模式" if new_mode == "toggle" else "按住模式"
            self.system_tray.show_message("录音模式", f"已切换到{mode_name}")
        
        # 更新选择的IP
        new_ip = settings.get('selected_ip')
        if new_ip is not None:
            old_ip = self.config_manager.get('selected_ip')
            if new_ip != old_ip:
                self.config_manager.set('selected_ip', new_ip)
                # 更新主窗口显示的IP
                display_ip = new_ip if new_ip else self.config_manager.get_local_ip()
                self.main_window.ip_label.setText(f"📡 本机IP: {display_ip}")
                self.system_tray.show_message("IP地址", f"已更新IP: {display_ip}")
        
        # 更新端口（需要重启网络服务）
        new_port = settings.get('port')
        if new_port and new_port != self.config_manager.get('port'):
            self.config_manager.set('port', new_port)
            QMessageBox.information(
                self.main_window,
                "提示",
                "端口更改需要重启程序才能生效"
            )
        
        # 更新开机自启动
        auto_start = settings.get('auto_start')
        if auto_start != self.config_manager.get('auto_start'):
            self.config_manager.set('auto_start', auto_start)
            if auto_start:
                StartupManager.enable_startup()
            else:
                StartupManager.disable_startup()
        
        # 更新自动重连
        auto_rejoin = settings.get('auto_rejoin')
        if auto_rejoin is not None:
            self.config_manager.set('auto_rejoin', auto_rejoin)
        
        # 更新开机启动时最小化
        start_minimized = settings.get('start_minimized')
        if start_minimized is not None:
            self.config_manager.set('start_minimized', start_minimized)
    
    def on_toggle_mute(self):
        """切换静音"""
        self.is_muted = not self.is_muted
        self.config_manager.set('muted', self.is_muted)
        
        status = "已静音" if self.is_muted else "已取消静音"
        self.system_tray.show_message("静音状态", status)
    
    def on_hotkey_pressed(self):
        """快捷键按下"""
        print("[Main] ========================================")
        print("[Main] 收到 hotkey_pressed 信号")
        
        # 检查是否在房间中
        if not self.network_manager.in_room:
            print("[Main] 未加入房间，禁止录音")
            self.system_tray.show_message(
                "提示",
                "请先创建或加入一个房间才能使用语音对讲",
                3000
            )
            return
        
        if self.is_muted:
            print("[Main] 当前已静音，忽略快捷键")
            return
        
        # 获取录音模式
        hotkey_mode = self.config_manager.get('hotkey_mode', 'ptt')
        print(f"[Main] 当前录音模式: {hotkey_mode}")
        print(f"[Main] 当前录音状态: {'正在录音' if self.is_recording else '未录音'}")
        
        if hotkey_mode == 'toggle':
            # 切换模式：按一下切换录音状态
            if self.is_recording:
                # 正在录音，停止录音
                print("[Main] Toggle模式 - 正在录音，准备停止")
                self._stop_recording()
            else:
                # 未录音，开始录音
                print("[Main] Toggle模式 - 未录音，准备开始")
                self._start_recording()
        else:
            # PTT按住模式：按下开始录音
            if not self.is_recording:
                print("[Main] PTT模式 - 准备开始录音")
                self._start_recording()
            else:
                print("[Main] PTT模式 - 已经在录音，忽略")
    
    def on_hotkey_released(self):
        """快捷键松开"""
        print("[Main] ========================================")
        print("[Main] 收到 hotkey_released 信号")
        
        # 只在PTT模式下处理松开事件
        hotkey_mode = self.config_manager.get('hotkey_mode', 'ptt')
        print(f"[Main] 当前录音模式: {hotkey_mode}")
        print(f"[Main] 当前录音状态: {'正在录音' if self.is_recording else '未录音'}")
        
        if hotkey_mode == 'ptt':
            # PTT模式：松开停止录音
            if self.is_recording:
                print("[Main] PTT模式 - 正在录音，准备停止")
                self._stop_recording()
            else:
                print("[Main] PTT模式 - 未在录音状态，无需操作")
        else:
            print("[Main] Toggle模式 - 忽略松开事件")
    
    def _start_recording(self):
        """开始录音"""
        print("[Main] ---> _start_recording() 开始")
        print(f"[Main] 设置 is_recording = True")
        self.is_recording = True
        print("[Main] 调用 audio_manager.start_recording()")
        self.audio_manager.start_recording()
        print("[Main] <--- _start_recording() 完成")
    
    def _stop_recording(self):
        """停止录音"""
        print("[Main] ---> _stop_recording() 开始")
        print(f"[Main] 设置 is_recording = False")
        self.is_recording = False
        print("[Main] 调用 audio_manager.stop_recording()")
        audio_data = self.audio_manager.stop_recording()
        
        # 注意：音频已经通过on_audio_chunk_received实时发送了
        # 这里不再需要发送完整音频，避免重复发送
        print(f"[Main] 录音已停止，总音频大小: {len(audio_data) if audio_data else 0} 字节")
        print("[Main] (音频已实时传输，无需再次发送)")
        print("[Main] <--- _stop_recording() 完成")
    
    def on_recording_started(self):
        """录音开始"""
        print("[Main] ##### on_recording_started() 被调用 #####")
        print("[Main] 调用 recording_overlay.show_overlay()")
        self.recording_overlay.show_overlay()
        print("[Main] recording_overlay.show_overlay() 已调用")
    
    def on_audio_chunk_received(self, audio_chunk: bytes):
        """实时接收音频块并发送（实现实时传输）"""
        # 边录音边发送，实现实时对讲
        if audio_chunk and len(audio_chunk) > 0:
            print(f"[Main] >>> 发送音频块: {len(audio_chunk)} 字节")
            self.network_manager.send_audio(audio_chunk)
        else:
            print(f"[Main] 警告：收到空音频块")
    
    def on_recording_stopped(self, audio_data: bytes):
        """录音停止"""
        print("[Main] ##### on_recording_stopped() 被调用 #####")
        print(f"[Main] 音频数据大小: {len(audio_data) if audio_data else 0} 字节")
        print("[Main] !!! 关键：调用 recording_overlay.hide_overlay() !!!")
        self.recording_overlay.hide_overlay()
        print("[Main] recording_overlay.hide_overlay() 已调用")
        # 注意：音频已经实时发送了，这里不再需要发送完整音频
    
    def on_audio_received(self, user_name: str, audio_data: bytes):
        """接收到音频（在网络线程中被调用）"""
        # 立即播放音频（音频播放是线程安全的）
        try:
            self.audio_manager.play_audio(audio_data)
        except Exception as e:
            # 减少错误日志频率
            pass
        
        # 使用信号通知主线程处理UI更新（线程安全）
        self.audio_received_signal.emit(user_name, audio_data)
    
    def _handle_audio_received_in_main_thread(self, user_name: str, audio_data: bytes):
        """在主线程中处理音频接收（UI更新）"""
        # 更新该用户的最后音频时间
        import time
        current_time = time.time()
        
        # 如果是首次收到该用户的音频，显示通知
        if user_name not in self.last_audio_time:
            # print(f"[Main] 显示 {user_name} 的说话通知")
            try:
                self.speaking_notification.show_notification(user_name)
            except Exception as e:
                print(f"[Main] 显示通知失败: {e}")
        
        # 更新最后音频时间
        self.last_audio_time[user_name] = current_time
    
    def on_member_joined(self, user_name: str, user_ip: str):
        """成员加入"""
        self.system_tray.show_message("成员加入", f"{user_name} 加入了房间")
        self.on_members_updated(self.network_manager.get_members_list())
    
    def on_member_left(self, user_name: str):
        """成员离开"""
        self.system_tray.show_message("成员离开", f"{user_name} 离开了房间")
        self.on_members_updated(self.network_manager.get_members_list())
    
    def _restore_members(self, saved_members):
        """恢复保存的成员列表（房主重连时通知之前的成员）"""
        
        # 获取房主自己的IP（用于排除）
        local_ip = self.config_manager.get_local_ip()
        
        # 提取历史成员的IP列表（排除房主自己，仅用于发送通知）
        member_ips = []
        for member_data in saved_members:
            ip = member_data.get('ip')
            name = member_data.get('name')
            if ip and name:
                # 排除房主自己
                if ip == local_ip:
                    print(f"[Main] 跳过房主自己: {name} ({ip})")
                    continue
                
                member_ips.append(ip)
                print(f"[Main] 发现历史成员: {name} ({ip})")
        
        # 如果是房主，延迟通知所有之前的成员房间已重启
        # 注意：不直接添加到成员列表，等成员发送JOIN后再添加
        if self.network_manager.is_host:
            if member_ips:
                print(f"[Main] 房主重连，将在1秒后通知 {len(member_ips)} 个历史成员（已排除自己）")
                print(f"[Main] 当前房间成员：仅房主自己")
                print(f"[Main] 等待成员响应后将自动加入...")
                # 使用QTimer延迟发送通知，确保网络服务已准备就绪
                QTimer.singleShot(1000, lambda: self._delayed_notify_members(member_ips))
            else:
                print(f"[Main] 没有找到其他历史成员，房间当前只有房主自己")
        
        # 仅更新UI显示，不保存成员列表（避免覆盖历史数据）
        # 当成员真正加入时，会通过on_member_joined触发on_members_updated并保存
        self.main_window.update_members(self.network_manager.get_members_list())
    
    def _delayed_notify_members(self, member_ips):
        """延迟通知成员（确保网络服务已就绪）"""
        print(f"[Main] 开始通知 {len(member_ips)} 个成员重新加入房间")
        self.network_manager.notify_room_restart(member_ips)
        print(f"[Main] 通知已发送，等待成员响应...")
    
    def on_members_updated(self, members):
        """成员列表更新"""
        self.main_window.update_members(members)
        
        # 保存成员列表到配置
        room_name = self.config_manager.get('room_name')
        if room_name:
            members_data = [{"name": m.name, "ip": m.ip} for m in members]
            self.config_manager.save_room_members(room_name, members_data)
    
    def _check_audio_timeout(self):
        """检查音频接收超时，自动隐藏说话通知"""
        import time
        current_time = time.time()
        
        # 检查是否有用户超时未发送音频
        users_to_remove = []
        for user_name, last_time in self.last_audio_time.items():
            if (current_time - last_time) * 1000 > self.audio_timeout_ms:
                # 超时，隐藏该用户的说话通知
                print(f"[Main] {user_name} 说话结束，隐藏通知")
                self.speaking_notification.hide_notification()
                users_to_remove.append(user_name)
        
        # 移除超时的用户
        for user_name in users_to_remove:
            del self.last_audio_time[user_name]
    
    def on_quit(self):
        """退出程序"""
        print("[Main] ========== 程序退出 ==========")
        
        try:
            # 停止音频超时检查定时器
            if self.check_audio_timer:
                self.check_audio_timer.stop()
        except Exception as e:
            print(f"[Main] 停止定时器异常: {e}")
        
        try:
            # 先停止录音（如果正在录音）
            if self.is_recording:
                print("[Main] 停止录音...")
                self._stop_recording()
        except Exception as e:
            print(f"[Main] 停止录音异常: {e}")
        
        try:
            # 注销快捷键
            print("[Main] 注销快捷键...")
            self.hotkey_manager.cleanup()
        except Exception as e:
            print(f"[Main] 注销快捷键异常: {e}")
        
        try:
            # 停止网络服务
            print("[Main] 停止网络服务...")
            self.network_manager.stop()
        except Exception as e:
            print(f"[Main] 停止网络异常: {e}")
        
        try:
            # 清理音频（最后清理，确保其他组件先停止）
            print("[Main] 清理音频资源...")
            self.audio_manager.cleanup()
        except Exception as e:
            print(f"[Main] 清理音频异常: {e}")
        
        print("[Main] 程序退出完成")
        
        # 退出应用
        QApplication.quit()


def main():
    """主函数"""
    # 检测是否是开机自动启动
    is_autostart = '--autostart' in sys.argv
    
    # 创建应用
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)  # 关闭窗口不退出程序
    
    # 设置应用信息
    app.setApplicationName("LAN对讲机")
    app.setOrganizationName("WalkieTalkie")
    
    # 设置应用图标
    from ui.icon_loader import load_app_icon
    app.setWindowIcon(load_app_icon())
    
    # 如果是开机启动，先标记到配置中
    if is_autostart:
        from config.config_manager import ConfigManager
        config = ConfigManager()
        config.set('is_autostart_session', True)
        print("[Main] 检测到开机自动启动")
    
    # 创建主控制器
    walkie_talkie = WalkieTalkieApp()
    
    # 运行应用
    sys.exit(app.exec())


if __name__ == "__main__":
    main()

